package com.mingle.iwalk;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.GeoPoint;
import com.baidu.mapapi.MapActivity;
import com.baidu.mapapi.MapController;
import com.baidu.mapapi.MapView;
import com.baidu.mapapi.Overlay;
import com.baidu.mapapi.OverlayItem;
/*import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import android.app.Activity;*/
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.database.Cursor;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.text.InputType;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.Toast;
import android.widget.ViewAnimator;

public class TrackActivity extends MapActivity {

	private EditText mTheme;
	private EditText mDescription;
	private StatusButton mLocationBtn;
	private StatusButton mUploadBtn;
	
	private ListView mPOIList;
	private MapView mMapView;
	private List<Overlay> mMapOverlays; 
	private MapController  mMapController;
	
	private IndicateLayout mTrackCountIndicator;
	private IndicateLayout mPOICountIndicator;
	private IndicateLayout mTimeSyncIndicator;
	
	private TravelerDB mDB;
	private TrackInfo mInfo;
	private File mWorkFolder;
	private ViewAnimator mViewSwitcher;
	
	private  TravelerInfoCursorAdapter mLocAdapter;
	private BMapManager mBmapMan;
	private POIItemizedOverlay mPOIOverlay;
	
	private Thread mUploadThread;
	
	private final int HANDLER_MSG_UPLOAD_INFO_START = 9;
	private final int HANDLER_MSG_UPLOAD_INFO_END = 10;
	
	private final int LOCATE_STATE_NOT_LOCATING = 0;
	private final int LOCATE_STATE_LOCATING = 1;
	
	private final int UPLOAD_STATE_NO_UPLOAD = 0;
	private final int UPLOAD_STATE_UPLOADING = 1;
	
	private ITrackService mService = null;
	private ServiceConnection osc = new ServiceConnection() {

		public void onServiceConnected(ComponentName name, IBinder binder) {
			mService = ITrackService.Stub.asInterface(binder);
			try {
				if((mService.getTrackServiceState() == TrackService.TRACK_SERVICE_STATUS_IDLE) && (mInfo.id == TravelerInfo.INFO_INVALID_ID))
				{
					//not in tracking, new track info
					mService.startRecord(mTrackListener);
					
					upDateTrackCountIndicator(0);
					upDatePOICountIndicator(0);
					
					setLocate(LOCATE_STATE_LOCATING);
					mLocationBtn.setEnabled(true);
					
					if(mInfo.uploadFlag)
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(false);
					}
					else
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(true);
					}
				}
				else if((mService.getTrackServiceState() == TrackService.TRACK_SERVICE_STATUS_IDLE))
				{
					//not in tracking, view track info
					loadRelativePOIs();
					setLocate(LOCATE_STATE_NOT_LOCATING);
					mLocationBtn.setEnabled(false);
					
					if(mInfo.uploadFlag)
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(false);
					}
					else
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(true);
					}
				}
				else if((mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE) && (mInfo.uuid == mService.getTrackUUID()))
				{
					//in tracking, view tracking info
					loadRelativePOIs();
					List<Location> locInfoList = mService.setTrackListener(mTrackListener);
					for(Location info : locInfoList)
					{
						sendMessage(TrackService.TRACK_SERVICE_NOTIFY_LOC, info, TravelerInfo.INFO_INVALID_ID);
					}
					
					setLocate(LOCATE_STATE_LOCATING);
					mLocationBtn.setEnabled(true);
					
					if(mInfo.uploadFlag)
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(false);
					}
					else
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(true);
					}
					
				}
				else if((mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE) && (mInfo.uuid != mService.getTrackUUID()))
				{
					//in tracking, view other track info
					loadRelativePOIs();
					
					setLocate(LOCATE_STATE_NOT_LOCATING);
					mLocationBtn.setEnabled(false);
					
					if(mInfo.uploadFlag)
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(false);
					}
					else
					{
						setUpload(UPLOAD_STATE_NO_UPLOAD);
						mUploadBtn.setEnabled(true);
					}
				}
				
			} catch (RemoteException e) {
				
				e.printStackTrace();
			}

		}

		public void onServiceDisconnected(ComponentName name) {
			mService = null;
			
		}
	
	 };
	 
	 private void loadRelativePOIs()
	 {
		 try {
				List<POIInfo> relativePOIInfos = mDB.getRelativePOIInfo(mInfo.uuid);
				if(relativePOIInfos != null)
				{
					for(POIInfo poiInfo : relativePOIInfos)
					{
						if(poiInfo.location == null)
						{
							continue;
						}
						GeoPoint orig_point=new GeoPoint((int)(poiInfo.location.getLatitude() * 1E6), (int)(poiInfo.location.getLongitude() * 1E6));
		 				OverlayItem overlayitem = new OverlayItem(orig_point, getContext().getResources().getString(R.string.loc_info), null /*snip*/);   

		 				mPOIOverlay.addOverlay(overlayitem, poiInfo.id, POIItemizedOverlay.POIITEM_ACTION_SHOW_DETAIL_INFO);
		 				mMapOverlays.add(mPOIOverlay);
		 				
		 				mMapController.setCenter(orig_point);
					}
					mLocAdapter.notifyDataSetChanged();
	 				
					mMapController.setZoom(14); 
	 				mMapView.invalidate();
				}
				
				upDateTrackCountIndicator(mInfo.trackList.size());
				upDatePOICountIndicator(relativePOIInfos.size());
				
			} catch (Exception e) {
				e.printStackTrace();
			}
	 }
	 
	 private Handler mHandler= new Handler()
	 {
		 @Override
		 public void handleMessage(Message msg) {

			 switch(msg.what) {
			 	case TrackService.TRACK_SERVICE_NOTIFY_LOC:
			 	{
			 		Location loc = (Location)msg.obj;

			 		if(loc == null)
			 		{
			 			return;
			 		}
			 		
			 		mInfo.trackList.add(loc);
			 		upDateTrackCountIndicator(mInfo.trackList.size());
			 		
			 		GeoPoint orig_point=new GeoPoint((int)(loc.getLatitude() * 1E6), (int)(loc.getLongitude() * 1E6));
			 		mMapController.setCenter(orig_point);
			 		mMapView.invalidate();
			 	}
	            break;
	            
			 	case HANDLER_MSG_UPLOAD_INFO_START:
		            {
		            }
		            break;
		            
		        case HANDLER_MSG_UPLOAD_INFO_END:
		            {
		            	if(msg.arg1 == 0)
		            	{
		            		mInfo.uploadFlag = true;
		            		mDB.saveUploadFlag(TravelerInfo.INFO_TYPE_POI, mInfo.id, mInfo.uploadFlag);
		            		updateTimeSyncInd();
		            		mUploadBtn.setText(R.string.upload);
		            		mUploadBtn.showIcon();
		            		mUploadBtn.setEnabled(false);
		            	}
		            	else
		            	{
		            		mUploadBtn.setText(R.string.upload);
		            		mUploadBtn.showIcon();
		            		mUploadBtn.setEnabled(true);
		            		Toast.makeText(getContext(), R.string.unload_fail, Toast.LENGTH_LONG).show();
		            	}
		            }
		            break;
	            
			 	case TrackService.TRACK_SERVICE_NOTIFY_STOP:
			 	{
			 		
			 	}
			 	break;
			 }
		 }
	};
	
	private void sendMessage(int type, Object obj, int extra)
	{
		Message m = mHandler.obtainMessage(type, extra, 0, obj);
		mHandler.sendMessage(m);
	}
	
	private void upDateTrackCountIndicator(int count)
	{
		mTrackCountIndicator.mProgressBar.setVisibility(View.GONE);
		mTrackCountIndicator.mIcon.setVisibility(View.VISIBLE);
		mTrackCountIndicator.mInfo.setVisibility(View.VISIBLE);
		Resources res = getContext().getResources();
		mTrackCountIndicator.mInfo.setText(res.getString(R.string.track_count) + String.valueOf(count));
	}
	
	private void upDatePOICountIndicator(int count)
	{
		mPOICountIndicator.mProgressBar.setVisibility(View.GONE);
		mPOICountIndicator.mIcon.setVisibility(View.VISIBLE);
		mPOICountIndicator.mInfo.setVisibility(View.VISIBLE);
		Resources res = getContext().getResources();
		mPOICountIndicator.mInfo.setText(res.getString(R.string.poi_count) +  String.valueOf(count));
	}
	
	 private ITrackServiceListener mTrackListener = new ITrackServiceListener()
	 {

		@Override
		public IBinder asBinder() {
			return null;
		}

		@Override
		public void onNotify(int type, Location loc, int poiId)
				throws RemoteException {
			
			sendMessage(type, loc, poiId);	
		}
		 
	 };
	 
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.track_layout);
        
        Button exitBtn = (Button) findViewById(R.id.exit_btn);
        exitBtn.setOnClickListener(mExitListener);
        
        Button saveDeleteBtn = (Button) findViewById(R.id.save_delete_btn);
        saveDeleteBtn.setOnClickListener(mSaveDeleteListener);
        
        RadioButton listType = (RadioButton) findViewById(R.id.list_type); 
        RadioButton mapType = (RadioButton) findViewById(R.id.map_type); 
        listType.setOnCheckedChangeListener(mOnCheckChangedListener);
        mapType.setOnCheckedChangeListener(mOnCheckChangedListener);
        mViewSwitcher = (ViewAnimator) findViewById(R.id.content_switcher);
        
        mTheme = (EditText) findViewById(R.id.theme);
        mDescription = (EditText) findViewById(R.id.desctiption);
        
        mLocationBtn = (StatusButton) findViewById(R.id.loc_btn);
        mLocationBtn.setOnClickListener(mLocationBtnListener);
        mUploadBtn = (StatusButton) findViewById(R.id.upload_btn);
        mUploadBtn.setOnClickListener(mUploadBtnListener);
        
        mTrackCountIndicator = (IndicateLayout) findViewById(R.id.track_count_ind);
        mPOICountIndicator = (IndicateLayout) findViewById(R.id.poi_count_ind);
        mTimeSyncIndicator = (IndicateLayout) findViewById(R.id.time_sync_ind);
        
        mBmapMan = new BMapManager(getApplication());
		mBmapMan.init("15CEF55B47A59959AB2325755DD60E1F17A2ACBE", null);
		super.initMapActivity(mBmapMan);
        mMapView = (MapView) findViewById(R.id.map_view);
        mMapView.setClickable(true);
        mMapView.setBuiltInZoomControls(true);
        mMapOverlays = mMapView.getOverlays(); 
        mMapController = mMapView.getController();
		
		mPOIList = (ListView) findViewById(R.id.list_view);
		mDB = TravelerDB.getInstance(getContext());

        int id = getIntent().getIntExtra("INFO_ID", TravelerInfo.INFO_INVALID_ID);
		if(id != TravelerInfo.INFO_INVALID_ID)
		{ 
			saveDeleteBtn.setText(R.string.delete);
			mInfo = (TrackInfo) mDB.getTravelerInfo(id, TravelerInfo.INFO_TYPE_TRACK);
			mTheme.setText(mInfo.title);
			mTheme.setEnabled(false);
			mTheme.setInputType(InputType.TYPE_NULL); 
			mDescription.setText(mInfo.description);
			mDescription.setEnabled(false); 
			mDescription.setInputType(InputType.TYPE_NULL); 
			
			Cursor poiCursor = mDB.getRelativePOIInfos(mInfo.uuid, TravelerInfo.INFO_TYPE_POI);
		 	mLocAdapter = new TravelerInfoCursorAdapter(getContext(), mService, R.layout.poi_item, R.layout.track_item, poiCursor, true);
		 	mPOIList.setAdapter(mLocAdapter);
		 	mPOIList.setOnItemClickListener(mOnPOIListClickListener);
		
		}
		else
		{
			saveDeleteBtn.setText(R.string.save);
			mTheme.setEnabled(false);
			mTheme.setInputType(InputType.TYPE_NULL); 
			mDescription.setSelected(true);
			mInfo = new TrackInfo();

			Date date = Calendar.getInstance().getTime();
			mInfo.createTime = date.getTime();
			mInfo.uuid = (int)mInfo.createTime;
			Calendar cal = Calendar.getInstance();
			mInfo.workingFolderPath = TravelerConfig.APP_DATA_FOLDER +
						 String.valueOf(cal.get(Calendar.YEAR))+ "_" +
						 String.valueOf(cal.get(Calendar.MONTH)+1)+ "_" +
						 String.valueOf(cal.get(Calendar.DAY_OF_MONTH))+ "_" +
						 String.valueOf(cal.get(Calendar.HOUR_OF_DAY))+ "_" +
						 String.valueOf(cal.get(Calendar.MINUTE));
		}

		if(mInfo.trackList == null)
		{
			mInfo.trackList = new ArrayList<Location>();
		}
		
		initMapView(mInfo.trackList);
		
		updateTimeSyncInd();
		
		mWorkFolder = new File(mInfo.workingFolderPath);
		if(!mWorkFolder.exists())
    	{
			mWorkFolder.mkdirs();
    	}
		
		bindService((new Intent()).setClass(getContext(),TrackService.class), osc, 0);
	}
	
	private void initMapView(List<Location> locList)
	{
		TrackPathOverlay trackPathOverlay = new TrackPathOverlay(locList);
		mMapOverlays.add(trackPathOverlay);
		
		if(locList.size()!=0)
		{
			Location loc = locList.get(0);
			GeoPoint orig_point=new GeoPoint((int)(loc.getLatitude() * 1E6), (int)(loc.getLongitude() * 1E6));
			mMapController.setCenter(orig_point);
		}
 		
		mMapController.setZoom(14);
		mPOIOverlay = new POIItemizedOverlay(getContext().getResources().getDrawable(R.drawable.loc_pin),getContext());
		mMapView.invalidate();
	}
	
	private void updateTimeSyncInd()
	{
		mTimeSyncIndicator.mIcon.setVisibility(mInfo.uploadFlag?View.VISIBLE:View.GONE);
		mTimeSyncIndicator.mProgressBar.setVisibility(View.GONE);
		mTimeSyncIndicator.mInfo.setText(new Date(mInfo.createTime).toLocaleString());
		mTimeSyncIndicator.mInfo.setVisibility(View.VISIBLE);
	}

	private void setUpload(int action)
	{
		switch(action)
		{
		case UPLOAD_STATE_NO_UPLOAD:
		{
			mUploadBtn.setText(R.string.upload);
			mUploadBtn.showIcon();
		}
		break;
		
		case UPLOAD_STATE_UPLOADING:;
		{
			//mUploadBtn.setEnabled(true);
			mUploadBtn.setText(R.string.uploading);
			mUploadBtn.showProgressBar();
		}
		break;
		}
	}
	
	private void setLocate(int action)
	{
		switch(action)
		{
		case LOCATE_STATE_NOT_LOCATING:
		{
			mLocationBtn.showIcon();
			mLocationBtn.setText(R.string.locate);
		}
		break;
		
		case LOCATE_STATE_LOCATING:
		{
			mLocationBtn.showProgressBar();
			mLocationBtn.setText(R.string.stop_locate);
		}
		break;
		}
	}
	
	private OnClickListener mExitListener = new OnClickListener()
	{

		@Override
		public void onClick(View v) {
			
			try {
				if(mInfo.id == TravelerInfo.INFO_INVALID_ID && mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE )
				{
					mService.stopRecord();
				}
			} catch (RemoteException e) {
				
				e.printStackTrace();
			}
			
			finish();
		}
		
	};
	
	 private OnCheckedChangeListener mOnCheckChangedListener = new OnCheckedChangeListener()
	    {

			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				
				if(!isChecked)
				{
					return;
				}
				
				switch(buttonView.getId())
				{
				case R.id.list_type:
					{
						mViewSwitcher.setDisplayedChild(1);
					}
					break;
					
				case R.id.map_type:
					{
						mViewSwitcher.setDisplayedChild(0);
					}
					break;
				}
				
			}
	    	
	    };
	
	private OnClickListener mSaveDeleteListener = new OnClickListener()
	{

		@Override
		public void onClick(View v) {
			
			if(mInfo.id == TravelerInfo.INFO_INVALID_ID)
			{
				mInfo.title = mTheme.getText().toString();
				mInfo.description = mDescription.getText().toString();
				mInfo.trackPath = mInfo.workingFolderPath + "/track.xml";
				mInfo.id = mDB.saveTrackInfo(mInfo);
				if(mInfo.id != TravelerInfo.INFO_INVALID_ID)
				{
					try {
						mService.setTrackId(mInfo.id);
						mService.setTrackUUID(mInfo.uuid);
						mService.setTrackPath(mInfo.trackPath);
					} catch (RemoteException e) {
						
						e.printStackTrace();
					}
					((Button)v).setText(R.string.delete);
					mTheme.setEnabled(false);
					mDescription.setEnabled(false);
					
				}
			}
			else
			{
				mDB.deleteTravelerInfo(mInfo.id, TravelerInfo.INFO_TYPE_TRACK);
				mInfo.id = TravelerInfo.INFO_INVALID_ID;
				try {
					if((mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE) && (mInfo.id == TravelerInfo.INFO_INVALID_ID))
					{
						mService.stopRecord();
					}
				} catch (RemoteException e) {
					
					e.printStackTrace();
				}
				finish();
			}
		}
		
	};
	
	private OnItemClickListener mOnPOIListClickListener = new OnItemClickListener()
	{

		@Override
		public void onItemClick(AdapterView<?> parent, View v, int pos,
				long id) {
			Cursor c = (Cursor)mLocAdapter.getItem(pos);
			
			int infoId = c.getInt(c.getColumnIndex(TravelerDB._ID));
			
			if(infoId != TravelerInfo.INFO_INVALID_ID)
			{
				Intent i = new Intent(getContext(), POIActivity.class);
				i.putExtra("INFO_ID", infoId);
				startActivity(i);
			}
		}
		
	};
	
	private OnClickListener mLocationBtnListener = new OnClickListener()
	{

		@Override
		public void onClick(View v) {

			if(mInfo.id == TravelerInfo.INFO_INVALID_ID)
			{
				Toast.makeText(getContext(), R.string.not_save_yet, Toast.LENGTH_LONG).show();
				
				return;
			}
			
			try {
				if(mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE && TravelerInfo.INFO_INVALID_ID != mInfo.id)
				{
					//stop recording 
					mService.stopRecord();

					mDB.saveTrackCount(mInfo.id, (mInfo.trackList!=null?mInfo.trackList.size():0));
					setLocate(LOCATE_STATE_NOT_LOCATING);
					mLocationBtn.setEnabled(false);
				}
			} catch (RemoteException e) {
				
				e.printStackTrace();
			}
		}
		
	};
	

	
	private OnClickListener mUploadBtnListener = new OnClickListener()
	{

		@Override
		public void onClick(View v) {
			
			/*if(mInfo.uploadFlag)
			{
				return;
			}
			
			if(mUploadThread == null)
			{
				Runnable r = new Runnable()
				{
	
					@Override
					public void run() {
						sendMessage(HANDLER_MSG_UPLOAD_INFO_START, null,0);
						
						//TODO Idiot: call remote api
						int ret = Utils.uploadTravelInfo(mInfo, TravelerInfo.INFO_TYPE_TRACK);
						
						sendMessage(HANDLER_MSG_UPLOAD_INFO_END, null, ret);
						mUploadThread = null;
					}
				};
				
				mUploadThread = new Thread(r);
				mUploadThread.start();
				
				//updateUploadBtnStatus();
				mUploadBtn.setText(R.string.uploading);
				mUploadBtn.showProgressBar();
			}
			else
			{
				mUploadThread.stop();
				mUploadThread = null;
				//updateUploadBtnStatus();
				mUploadBtn.setText(R.string.upload);
				mUploadBtn.showIcon();
			}*/

			try {
				mService.addFakeLoc();
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
		
	};

    
	private Context getContext()
    {
    	return TrackActivity.this;
    }
	
	@Override
	protected void onPause() {
		if(mBmapMan != null)
		{
			mBmapMan.stop();
		}
		super.onPause();
	}

	@Override
	protected void onResume() {
		if(mBmapMan != null)
		{
			mBmapMan.start();
		}
		super.onResume();
	}
	
	@Override
	protected void onDestroy() {

		try {
			if(mInfo.id == TravelerInfo.INFO_INVALID_ID && mService.getTrackServiceState() != TrackService.TRACK_SERVICE_STATUS_IDLE)
			{
				mService.stopRecord();
			}
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		mWorkFolder.delete();

		unbindService(osc);
		
		if(mBmapMan != null)
		{
			mBmapMan.destroy();
			mBmapMan = null;
		}
		
		super.onDestroy();
	}

	@Override
	protected boolean isRouteDisplayed() {
		
		return false;
	}
	
}
